#ifndef LOGGER_HPP
#define LOGGER_HPP

/*
* 后续不够用的时候可替换为Spdlog（一款强大的日志库）
*/

#include <string>
#include <fstream>
#include <sstream>
#include <mutex>
#include <vector>
#include <memory>
#include <chrono>
#include <ctime>
#include <iostream>

namespace WaveGuard { // 定义命名空间

    /**
     * @brief 日志级别枚举，定义不同的日志严重程度
     */
    enum class LogLevel {
        DEBUG,    // 调试信息，用于开发阶段的详细信息
        INFO,     // 一般信息，用于记录系统运行状态
        WARNING,  // 警告信息，可能存在潜在问题
        ERROR,    // 错误信息，系统出现可恢复错误
        CRITICAL  // 严重错误，系统可能无法继续运行
    };

    /**
     * @brief 日志输出目标的抽象接口
     * 所有日志输出目标都应实现这个接口
     */
    class LogOutput {
    public:
        virtual ~LogOutput() = default;
        virtual void write(const std::string &message) = 0; // 纯虚函数，用于输出日志消息
    };

    /**
     * @brief 控制台输出实现
     * 将日志消息输出到标准输出
     */
    class ConsoleOutput : public LogOutput {
    public:
        void write(const std::string &message) override; // 实现输出到控制台的方法
    };

    /**
     * @brief 文件输出实现
     * 将日志消息输出到指定文件
     */
    class FileOutput : public LogOutput {
    private:
        std::ofstream fileStream;  // 文件流对象
        std::string filePath;      // 日志文件路径
        bool openFile();           // 打开文件的辅助方法

    public:
        explicit FileOutput(const std::string &filePath); // 构造函数，指定日志文件路径
        ~FileOutput() override;                           // 析构函数
        void write(const std::string &message) override;  // 实现输出到文件的方法
    };

    /**
     * @brief 日志系统核心类
     * 实现线程安全的单例模式日志系统
     */
    class Logger {
    private:
        static std::shared_ptr<Logger> instance;  // 单例实例
        static std::mutex instanceMutex;          // 用于单例创建的互斥锁

        LogLevel currentLevel;                    // 当前日志级别
        std::vector<std::shared_ptr<LogOutput>> outputs; // 输出目标列表
        std::mutex logMutex;                      // 用于日志写入的互斥锁
        bool enableTimestamp;                     // 是否启用时间戳
        bool enableThreadId;                      // 是否启用线程ID
        bool consoleOutputEnabled;                // 控制台输出启用标志

        Logger();                                 // 私有构造函数
        Logger(const Logger &) = delete;          // 禁用拷贝构造函数
        Logger &operator=(const Logger &) = delete; // 禁用赋值运算符

        // 允许std::make_shared访问私有构造函数
        friend class std::shared_ptr<Logger>;

        std::string formatMessage(LogLevel level, const std::string &message); // 格式化日志消息
        std::string getLevelString(LogLevel level); // 获取日志级别字符串表示
        std::string getTimestamp();                 // 获取当前时间戳字符串
        std::string getThreadId();                  // 获取当前线程ID字符串

    public:
        ~Logger() = default; // 公有析构函数

        static std::shared_ptr<Logger> getInstance(); // 获取单例实例的静态方法

        void setLogLevel(LogLevel level);             // 设置日志级别
        void addOutput(std::shared_ptr<LogOutput> output); // 添加输出目标
        void setEnableTimestamp(bool enable);         // 设置是否启用时间戳
        void setEnableThreadId(bool enable);          // 设置是否启用线程ID
        void setConsoleOutputEnabled(bool enabled);   // 设置是否输出到控制台

        // 不同级别日志记录方法
        void debug(const std::string &message);
        void info(const std::string &message);
        void warning(const std::string &message);
        void error(const std::string &message);
        void critical(const std::string &message);

        // 带格式化参数的日志记录模板方法
        template<typename... Args>
        void debug(const std::string &format, Args&&... args);

        template<typename... Args>
        void info(const std::string &format, Args&&... args);

        template<typename... Args>
        void warning(const std::string &format, Args&&... args);

        template<typename... Args>
        void error(const std::string &format, Args&&... args);

        template<typename... Args>
        void critical(const std::string &format, Args&&... args);
    };

    /**
     * @brief 记录DEBUG级别日志（带格式化参数）
     * @tparam Args 可变参数类型包
     * @param format 格式化字符串，使用类似printf的格式说明符
     * @param args 可变参数包，将被展开并传递给snprintf进行格式化
     * @details
     *  1. 检查当前日志级别是否允许输出DEBUG信息
     *  2. 使用snprintf将格式化字符串和参数组合为完整消息
     *  3. 加锁确保线程安全，将消息写入所有注册的输出目标
     * @note
     *  - 缓冲区大小限制为1024字节，超长消息会被截断
     *  - 参数类型必须与格式化字符串中的格式说明符匹配
     *  - 内部使用std::forward保持参数的左值/右值属性
     */
    template<typename... Args>
    void Logger::debug(const std::string &format, Args&&... args) {
        if (currentLevel > LogLevel::DEBUG) return;

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);

        std::lock_guard<std::mutex> lock(logMutex);
        for (auto &output : outputs) {
            output->write(formatMessage(LogLevel::DEBUG, buffer));
        }
    }

    /**
     * @brief 记录INFO级别日志（带格式化参数）
     * @tparam Args 可变参数类型包
     * @param format 格式化字符串，使用类似printf的格式说明符
     * @param args 可变参数包，将被展开并传递给snprintf进行格式化
     * @details 与debug()功能类似，但日志级别为INFO
     */
    template<typename... Args>
    void Logger::info(const std::string &format, Args&&... args) {
        if (currentLevel > LogLevel::INFO) return;

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);

        std::lock_guard<std::mutex> lock(logMutex);
        for (auto &output : outputs) {
            output->write(formatMessage(LogLevel::INFO, buffer));
        }
    }

    /**
     * @brief 记录WARNING级别日志（带格式化参数）
     * @tparam Args 可变参数类型包
     * @param format 格式化字符串，使用类似printf的格式说明符
     * @param args 可变参数包，将被展开并传递给snprintf进行格式化
     * @details 与debug()功能类似，但日志级别为WARNING
     */
    template<typename... Args>
    void Logger::warning(const std::string &format, Args&&... args) {
        if (currentLevel > LogLevel::WARNING) return;

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);

        std::lock_guard<std::mutex> lock(logMutex);
        for (auto &output : outputs) {
            output->write(formatMessage(LogLevel::WARNING, buffer));
        }
    }

    /**
     * @brief 记录ERROR级别日志（带格式化参数）
     * @tparam Args 可变参数类型包
     * @param format 格式化字符串，使用类似printf的格式说明符
     * @param args 可变参数包，将被展开并传递给snprintf进行格式化
     * @details 与debug()功能类似，但日志级别为ERROR
     */
    template<typename... Args>
    void Logger::error(const std::string &format, Args&&... args) {
        if (currentLevel > LogLevel::ERROR) return;

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);

        std::lock_guard<std::mutex> lock(logMutex);
        for (auto &output : outputs) {
            output->write(formatMessage(LogLevel::ERROR, buffer));
        }
    }

    /**
     * @brief 记录CRITICAL级别日志（带格式化参数）
     * @tparam Args 可变参数类型包
     * @param format 格式化字符串，使用类似printf的格式说明符
     * @param args 可变参数包，将被展开并传递给snprintf进行格式化
     * @details 与debug()功能类似，但日志级别为CRITICAL
     */
    template<typename... Args>
    void Logger::critical(const std::string &format, Args&&... args) {
        if (currentLevel > LogLevel::CRITICAL) return;

        char buffer[1024];
        snprintf(buffer, sizeof(buffer), format.c_str(), std::forward<Args>(args)...);

        std::lock_guard<std::mutex> lock(logMutex);
        for (auto &output : outputs) {
            output->write(formatMessage(LogLevel::CRITICAL, buffer));
        }
    }

} // namespace WaveGuard

// 全局日志宏定义，简化日志使用
#define LOG_DEBUG(...) WaveGuard::Logger::getInstance()->debug(__VA_ARGS__)
#define LOG_INFO(...) WaveGuard::Logger::getInstance()->info(__VA_ARGS__)
#define LOG_WARNING(...) WaveGuard::Logger::getInstance()->warning(__VA_ARGS__)
#define LOG_ERROR(...) WaveGuard::Logger::getInstance()->error(__VA_ARGS__)
#define LOG_CRITICAL(...) WaveGuard::Logger::getInstance()->critical(__VA_ARGS__)

#endif // LOGGER_HPP    